package main

/*
* Content: 通过反射获取变量类型、通过反射获取变量值、结构体反射
* --------------------------------------------------
* 反射-Go语言中文文档: https://topgoer.cn/docs/golang/chapter11-12
 */

import (
	"fmt"
	"reflect"
)

type User struct {
	Id   int
	Name string
	Age  int
}

// 绑定方法
func (u User) Hello() {
	fmt.Println("Hello")
}

// 通过反射获取变量类型
func reflect_type(myFloat64 interface{}) { // 参数是 interface{} 类型

	t := reflect.TypeOf(myFloat64)
	fmt.Printf("myFloat64 的类型是: %v\n", t)

	// kind()可以获取 具体类型
	k := t.Kind()
	fmt.Printf("myFloat64 的具体类型是: %v\n", k)

	// switch 操作
	switch k {
	case reflect.Float64: // 必须是 reflect.Float64
		fmt.Println("switch: 打印 reflect.Float64 分支!")
	case reflect.Float32:
		fmt.Println("switch: 打印 reflect.Float32 分支!")
	}

}

// 通过反射获取变量值
func reflect_value(myFloat64 interface{}) {

	t := reflect.ValueOf(myFloat64)
	fmt.Printf("myFloat64 的值是: %v\n", t)

	// kind()可以获取 具体值?
	k := t.Kind()
	fmt.Printf("myFloat64 的具体值是: %v\n", k)

	// switch 操作
	switch k {
	case reflect.Float64: // 必须是 reflect.Float64
		fmt.Printf("switch: 打印 myFloat64 的值: %v\n", myFloat64)
	}
}

// 查看结构体的 类型、字段和方法
func Poni(o interface{}) {

	// 获取结构体类型 t
	ts := reflect.TypeOf(o)
	fmt.Printf("结构体的类型是: %v\n", ts)

	// 获取结构体值   v
	vs := reflect.ValueOf(o)
	fmt.Printf("结构体的值是: %v\n", vs)

	// 可以获取所有属性
	// 获取结构体字段个数：t.NumField()
	for i := 0; i < ts.NumField(); i++ {
		// 取每个字段
		f := ts.Field(i)
		fmt.Printf("%s : %v\n", f.Name, f.Type) // f.Name: 字段名称   f.Type: 字段类型

		// 获取字段的值信息
		// Interface()：获取字段对应的值
		val := vs.Field(i).Interface()
		fmt.Printf("字段: %v 的值是: %v\n", ts.Field(i), val)
	}

	fmt.Println("=================方法====================")
	for i := 0; i < ts.NumMethod(); i++ {
		m := ts.Method(i)
		fmt.Printf("方法名: %v\n", m.Name)
		fmt.Printf("方法类型: %v\n", m.Type)
	}

}

func MyBagReflect() {

	// 通过反射修改值的操作都没有实现, 可以参考官方文档

	// 通过反射获取变量类型
	fmt.Println("--------------------通过反射获取变量类型--------------------")

	var myFloat64 float64 = 8.19

	// 调用函数: 通过反射获取变量类型
	reflect_type(myFloat64)

	// 通过反射获取变量值
	fmt.Println("--------------------通过反射获取变量值--------------------")

	// 调用函数: 通过反射获取变量值
	reflect_value(myFloat64)

	// 结构体反射
	fmt.Println("--------------------结构体反射--------------------")

	// 调用函数: 查看结构体的 类型、字段和方法
	xqz := User{1, "xqz", 18}
	Poni(xqz)

}
